//
//  NetworkManager.swift
//  YFWatchDemo WatchKit Extension
//
//  Created by FYWCQ on 2019/7/4.
//  Copyright © 2019 YFWCQ. All rights reserved.
//

import Foundation
import Moya
import Alamofire
import HandyJSON

/// 超时时长
private var requestTimeOut:Double = 30
///成功数据的回调
typealias successCallback = (([String : Any]) -> (Void))

typealias successObjectCallback = ((HandyJSON) -> (Void))


///失败的回调
typealias failedCallback = ((String) -> (Void))
///网络错误的回调
typealias errorCallback = ((Error?) -> (Void))



/// 基于Alamofire,网络是否连接，，这个方法不建议放到这个类中,可以放在全局的工具类中判断网络链接情况
/// 用get方法是因为这样才会在获取isNetworkConnect时实时判断网络链接请求，如有更好的方法可以fork
var isNetworkConnect: Bool {
    get{
        return true
    }
}


//func NetWorkRequest(_ target: API, completion: @escaping successCallback , failed:failedCallback?, errorResult:errorCallback?) {
//    if !isNetworkConnect{
//        print("提示用户网络似乎出现了问题")
//        return
//    }
////    Provider
//}




private func JSONResponseDataFormatter(_ data: Data) -> Data {
    do {
        let dataAsJSON = try JSONSerialization.jsonObject(with: data)
        let prettyData =  try JSONSerialization.data(withJSONObject: dataAsJSON, options: .prettyPrinted)
        return prettyData
    } catch {
        return data //fallback to original data if it cant be serialized
    }
}

///网络请求的基本设置,这里可以拿到是具体的哪个网络请求，可以在这里做一些设置
private let myEndpointClosure = { (target: API) -> Endpoint in
    ///这里把endpoint重新构造一遍主要为了解决网络请求地址里面含有? 时无法解析的bug https://github.com/Moya/Moya/issues/1198
    let url = target.baseURL.absoluteString + target.path
    var task = target.task
    
    /*
     如果需要在每个请求中都添加类似token参数的参数请取消注释下面代码
     👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
     */
    //    let additionalParameters = ["token":"888888"]
    //    let defaultEncoding = URLEncoding.default
    //    switch target.task {
    //        ///在你需要添加的请求方式中做修改就行，不用的case 可以删掉。。
    //    case .requestPlain:
    //        task = .requestParameters(parameters: additionalParameters, encoding: defaultEncoding)
    //    case .requestParameters(var parameters, let encoding):
    //        additionalParameters.forEach { parameters[$0.key] = $0.value }
    //        task = .requestParameters(parameters: parameters, encoding: encoding)
    //    default:
    //        break
    //    }
    /*
     👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆
     如果需要在每个请求中都添加类似token参数的参数请取消注释上面代码
     */
    
    
    var endpoint = Endpoint(
        url: url,
        sampleResponseClosure: { .networkResponse(200, target.sampleData) },
        method: target.method,
        task: task,
        httpHeaderFields: target.headers
    )
    requestTimeOut = 30//每次请求都会调用endpointClosure 到这里设置超时时长 也可单独每个接口设置
    
    
    return endpoint
//    switch target {
//    case .easyRequset:
//        return endpoint
//    case .register:
//        requestTimeOut = 5
//        return endpoint
//
//    default:
//        return endpoint
//    }
}



///网络请求的设置
private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
    do {
        var request = try endpoint.urlRequest()
        //设置请求时长
        request.timeoutInterval = requestTimeOut
        
        // 打印请求参数
        if let requestData = request.httpBody {
            print("\(request.url!)"+"\n"+"\(request.httpMethod ?? "")"+"发送参数"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
        }else{
            print("\(request.url!)"+"\(String(describing: request.httpMethod))")
        }
        done(.success(request))
    } catch {
        done(.failure(MoyaError.underlying(error, nil)))
    }
}


/// NetworkActivityPlugin插件用来监听网络请求，界面上做相应的展示
///但这里我没怎么用这个。。。 loading的逻辑直接放在网络处理里面了
private let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in
    
    print("networkPlugin \(changeType)")
    //targetType 是当前请求的基本信息
    switch(changeType){
    case .began:
        print("开始请求网络")
        
    case .ended:
        print("结束")
    }
}



//let Provider =  MoyaProvider<API>(plugins: [NetworkLoggerPlugin(verbose: true, responseDataFormatter: JSONResponseDataFormatter)])



////网络请求发送的核心初始化方法，创建网络请求对象
let Provider = MoyaProvider<API>(endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)







/// 最常用的网络请求，只需知道正确的结果无需其他操作时候用这个
///
/// - Parameters:
///   - target: 网络请求
///   - completion: 请求成功的回调
func NetWorkRequest(_ target: API, completion: @escaping successCallback ){
    NetWorkRequest(target, completion: completion, failed: nil, errorResult: nil)
}


/// 需要知道成功或者失败的网络请求， 要知道code码为其他情况时候用这个
///
/// - Parameters:
///   - target: 网络请求
///   - completion: 成功的回调
///   - failed: 请求失败的回调
func NetWorkRequest(_ target: API, completion: @escaping successCallback , failed:failedCallback?) {
    NetWorkRequest(target, completion: completion, failed: failed, errorResult: nil)
}


func NetWorkRequest(_ target: API, completion: @escaping successObjectCallback, reponceType:HandyJSON.Type , failed:failedCallback?,errorResult:errorCallback?) {
    
    NetWorkRequest(target, completion: { (json) -> (Void) in
        
        if let repon = reponceType.deserialize(from: json) {
            completion(repon)
        } else {
            if let  failedR = failed {
                failedR("数据格式错误")
            }
        }
       
    }, failed: failed, errorResult: errorResult)
    
}

func NetWorkRequest(_ target: API, completion: @escaping successObjectCallback, reponceType:HandyJSON.Type ,errorResult:errorCallback?) {

    NetWorkRequest(target, completion: { (json) -> (Void) in

        if let repon = reponceType.deserialize(from: json) {
            completion(repon)
        } else {
            if let errorResult = errorResult {
                errorResult(nil)
            }
        }
    }, failed: {(errorString) -> (Void) in
        if let errorResultR = errorResult {
            errorResultR(nil)
        }
    }, errorResult: errorResult)

}


///  需要知道成功、失败、错误情况回调的网络请求   像结束下拉刷新各种情况都要判断
///
/// - Parameters:
///   - target: 网络请求
///   - completion: 成功
///   - failed: 失败
///   - error: 错误
func NetWorkRequest(_ target: API, completion: @escaping successCallback , failed:failedCallback?, errorResult:errorCallback?) {
    //先判断网络是否有链接 没有的话直接返回--代码略
    if !isNetworkConnect{
        print("提示用户网络似乎出现了问题")
        return
    }
    
    //这里显示loading图
    Provider.request(target) { (result) in
        //隐藏hud
        switch result {
        case let .success(response):
            
            do {
                
                if let resJson: [String : Any] = try response.mapJSON() as? [String : Any] {
                    completion(resJson)
                } else {
                    if let failBlock = failed {
                        failBlock("数据格式错误")
                    }
                }

                
                
                //               这里的completion和failed判断条件依据不同项目来做，为演示demo我把判断条件注释了，直接返回completion。
                
//                completion(String(data: response.data, encoding: String.Encoding.utf8)!)
                
//                print("flag不为1000 HUD显示后台返回message"+"\(jsonData[RESULT_MESSAGE].stringValue)")
                
                //                if jsonData[RESULT_CODE].stringValue == "1000"{
                //                    completion(String(data: response.data, encoding: String.Encoding.utf8)!)
                //                }else{
                //                if failed != nil{
                //                    failed(String(data: response.data, encoding: String.Encoding.utf8)!)
                //                }
                //                }
                
            }
            catch {
//                errorResult!("")
                switch (error){
                   
                default: break
                    
                }
                if let failBlock = failed {
                    failBlock("数据格式错误")
                }
                
            }
        case let .failure(error):
            print("error print begin")
            print(error)
            
            let errorYF = error as NSError
            
            
            
//            guard let error = error as? NSError else {
//                //网络连接失败，提示用户
//                print("网络连接失败")
//                if errorResult != nil {
//                    errorResult!("")
//                }
//                break
//            }
            
            print("code\(errorYF.code)")
            
            if errorResult != nil {
                errorResult!(errorYF)
            }
        }
    }
}




/*   设置ssl
 let policies: [String: ServerTrustPolicy] = [
 "example.com": .pinPublicKeys(
 publicKeys: ServerTrustPolicy.publicKeysInBundle(),
 validateCertificateChain: true,
 validateHost: true
 )
 ]
 */

// 用Moya默认的Manager还是Alamofire的Manager看实际需求。HTTPS就要手动实现Manager了
//private public func defaultAlamofireManager() -> Manager {
//
//    let configuration = URLSessionConfiguration.default
//
//    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
//
//    let policies: [String: ServerTrustPolicy] = [
//        "ap.grtstar.cn": .disableEvaluation
//    ]
//    let manager = Alamofire.SessionManager(configuration: configuration,serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies))
//
//    manager.startRequestsImmediately = false
//
//    return manager
//}
